package com.fresh.bus.chat.business;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.query.SortQueryBuilder;
import org.springframework.data.redis.support.collections.DefaultRedisList;
import org.springframework.data.redis.support.collections.DefaultRedisSet;
import org.springframework.data.redis.support.collections.DefaultRedisZSet;
import org.springframework.data.redis.support.collections.RedisList;
import org.springframework.data.redis.support.collections.RedisSet;
import org.springframework.data.redis.support.collections.RedisZSet;

import com.fresh.bus.canoe.message.Response;
import com.fresh.bus.canoe.session.Session;
import com.fresh.bus.canoe.session.SessionRoleManager;
import com.fresh.bus.chat.ctrl.OpCodes;

public class ScheduleManager {
	private static final Logger log = LoggerFactory
			.getLogger(ScheduleManager.class);
	private final StringRedisTemplate template;

	private long lastSelectTime;

	@Resource
	private SystemConfig sysConfig;
	@Resource
	private UserService userService;
	@Resource
	private FriendService friendService;
	@Resource
	private SessionRoleManager roleManager;
	@Resource
	private ZhiFeiJiService feijiService;
	@Resource
	private MessageService msgService;

	@Autowired
	public ScheduleManager(StringRedisTemplate template) {
		this.template = template;
	}

	public Map<String, String> line(String lid) {
		BoundHashOperations<String, String, String> userOps = template
				.boundHashOps(KeyUtils.lid(lid));
		return userOps.entries();
	}

	public Map<String, String> room(String rid) {
		BoundHashOperations<String, String, String> userOps = template
				.boundHashOps(KeyUtils.rid(rid));
		return userOps.entries();
	}

	public Map<String, String> stop(String sid) {
		BoundHashOperations<String, String, String> userOps = template
				.boundHashOps(KeyUtils.sid(sid));
		return userOps.entries();
	}

	public Map<String, String> city(String cid) {
		BoundHashOperations<String, String, String> ops = template
				.boundHashOps(KeyUtils.cid(cid));
		return ops.entries();
	}

	public RedisZSet<String> males(String rid) {
		return new DefaultRedisZSet<String>(KeyUtils.males(rid), template);
	}

	public RedisZSet<String> females(String rid) {
		return new DefaultRedisZSet<String>(KeyUtils.females(rid), template);
	}

	private RedisList<String> rooms(String sid) {
		return new DefaultRedisList<String>(KeyUtils.rooms(sid), template);
	}

	private RedisList<String> lines(String sid) {
		return new DefaultRedisList<String>(KeyUtils.lines(sid), template);
	}

	private DefaultRedisList<String> stops(String lid) {
		return new DefaultRedisList<String>(KeyUtils.stations(lid), template);
	}

	public DefaultRedisSet<String> fans(String uid) {
		return new DefaultRedisSet<String>(KeyUtils.fans(uid), template);
	}

	public DefaultRedisZSet<String> queue(String rid) {
		return new DefaultRedisZSet<String>(KeyUtils.queue(rid), template);
	}

	public List<Map<String, String>> candidate(String rid) {
		Set<String> candidate = null;
		RedisZSet<String> mr = this.males(rid);
		RedisZSet<String> fr = this.females(rid);
		if (mr.size() > 0) {
			candidate = mr;
		} else {
			candidate = fr;
		}

		List<Map<String, String>> candidateList = new ArrayList<Map<String, String>>();

		for (String id : candidate) {
			candidateList.add(this.userService.findUser(id));
		}
		return candidateList;
	}

	public void doIt() {
	}

	private List<String> covertSidsToNames(String key) {
		return template.sort(SortQueryBuilder.sort(key).noSort()
				.get("uid:*->name").build());
	}

	public String findNextStop(String lid, String targetSid, Boolean isUp) {
		DefaultRedisList<String> redList = this.stops(lid);
		List<String> stops = redList.range(0, -1);
		int index = stops.indexOf(targetSid);
		int size = stops.size();

		if (isUp) {
			index++;
		} else {
			index--;
		}

		if (index < 0) {
			index = size - 1;
		} else if (index >= size) {
			index = 0;
		}

		log.debug("Next station index is " + index);
		String sid = stops.get(index);
		return sid;
	}

	public List<Map<String, String>> findStationsByLine(String lid) {
		ArrayList<Map<String, String>> list = new ArrayList<Map<String, String>>();
		for (String sid : this.stops(lid)) {
			list.add(this.stop(sid));
		}
		return list;
	}

	public List<Map<String, String>> findRoomByStation(final String sid) {
		ArrayList<Map<String, String>> list = new ArrayList<Map<String, String>>();
		for (String rid : this.rooms(sid)) {
			list.add(this.room(rid));
		}
		return list;
	}

	public List<Map<String, String>> getCities() {
		RedisSet<String> cities = new DefaultRedisSet<String>(
				KeyUtils.cities(), template);
		ArrayList<Map<String, String>> list = new ArrayList<Map<String, String>>();
		for (String cid : cities) {
			list.add(this.city(cid));
		}
		return list;
	}

	public List<Map<String, Object>> findLineByStation(final String sid) {
		ArrayList<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
		for (String lid : this.lines(sid)) {
			Map<String, Object> map = new HashMap<String, Object>();
			map.put("line", line(lid));
			String rid = this.stop(sid).get("room");
			map.put("room", room(rid));
			list.add(map);
		}
		return list;
	}

	public void enterQueue(Session session) {
		String id = String.valueOf(session.getRole().getId());
		Map<String, String> user = this.userService.findUser(id);
		String rid = (String) session.getAttribute("rid");
		String sex = user.get("sex");
		RedisZSet<String> mr = this.males(rid);
		RedisZSet<String> fr = this.females(rid);

		if (sex.equals("female")) {
			fr.add(id);
		}
		if (sex.equals("male")) {
			mr.add(id);
		}
		synWaiterNum(rid);
	}

	public void synWaiterNum(String rid) {
		BoundHashOperations<String, String, String> ops = template
				.boundHashOps(KeyUtils.rid(rid));
		RedisZSet<String> mr = this.males(rid);
		RedisZSet<String> fr = this.females(rid);
		ops.put("maleNum", String.valueOf(mr.size()));
		ops.put("femaleNum", String.valueOf(fr.size()));

		Response response;
		Session session;
		response = new Response(OpCodes.WAITER_NUM);
		Map<String, String> map = new HashMap<String, String>();
		map.put("maleNum", String.valueOf(ops.get("maleNum")));
		map.put("femaleNum", String.valueOf(ops.get("femaleNum")));
		response.setData(map);
		for (String i : mr) {
			try {
				session = roleManager.getSession(i);
				if (session != null) {
					session.send(response);
				} else {
					mr.remove(i);
				}
			} catch (Exception ex) {
				mr.remove(i);
				log.error(ex.getMessage(), ex);
			}
		}

		for (String j : fr) {
			try {
				session = roleManager.getSession(j);
				if (session != null) {
					session.send(response);
				} else {
					fr.remove(j);
				}
			} catch (Exception ex) {
				fr.remove(j);
				log.error(ex.getMessage(), ex);
			}
		}
	}

	public void leftQueue(Session session) {
		String id = session.getRole().getId();
		Map<String,String> user = this.userService.findUser(id);
		String rid = (String) session.getAttribute("rid");

		RedisZSet<String> mr = this.males(rid);
		RedisZSet<String> fr = this.females(rid);
		RedisZSet<String> queue = this.queue(rid);

		String sex = user.get("sex");

		try {
			if (sex.equals("male")) {
				mr.remove(id);
			} else {
				fr.remove(id);
			}
			if (queue.rank(id) != null)
				queue.remove(id);
		} catch (Exception e) {
			log.error(e.getMessage(), e);
		}
		this.synWaiterNum(rid);
	}

	public void notifyCandidate(Session session, String question) {
		Set<String> candidateList;
		String id = session.getRole().getId();
		String rid = (String) session.getAttribute("rid");
		BoundHashOperations<String, String, String> user = this.template
				.boundHashOps(KeyUtils.uid(id));
		String sex = String.valueOf(user.get("sex"));
		if (sex.equals("female")) {
			candidateList = this.males(rid);
		} else {
			candidateList = this.females(rid);
		}

		for (String i : candidateList) {
			try {
				Response response = new Response(OpCodes.BEGIN_WAIT);
				Map<String, String> f = this.friendService.friend(i, id);
				Map<String, Object> map = new HashMap<String, Object>();
				map.put("words", question);
				map.put("asso", f);
				map.put("user", id);
				response.setData(map);
				roleManager.getSession(i).send(response);
			} catch (Exception ex) {
				log.error("Handler user " + i + " failed...", ex);
				continue;
			}
		}
	}

	public void setTalker(String to, String id) {
		Set<String> fans = this.fans(id);

		Session sio1 = roleManager.getSession(id);
		sio1.setAttribute("to", to);
		sio1.setAttribute("isTalking", "true");
		this.leftQueue(sio1);
		fans.remove(id);

		Session sio2 = roleManager.getSession(to);
		sio2.setAttribute("to", id);
		sio2.setAttribute("isTalking", "true");
		this.leftQueue(sio2);
		fans.remove(to);

		// 通知其他参选者
		Session s;
		Response res = new Response(OpCodes.END_SEL_TALKER);
		for (String u : this.fans(id)) {
			s = this.roleManager.getSession(u);
			Map<String, String> map = new HashMap<String, String>();
			map.put("winUser", to);
			map.put("aimUser", id);
			res.setData(map);
			s.send(res);
		}
		this.template.delete(KeyUtils.fans(id));

	}

	public void cancelElection(String id, String rid) {
		Set<String> fans = this.fans(id);
		fans.remove(id);
		BoundHashOperations<String, String, String> room = template
				.boundHashOps(KeyUtils.rid(rid));
		room.delete("isSelecting");
		// 通知其他参选者
		Session s;
		Response res = new Response(OpCodes.CANCEL_SEL_TALKER);
		for (String u : this.fans(id)) {
			s = this.roleManager.getSession(u);
			res.setData(true);
			if (s != null)
				s.send(res);
		}
		this.template.delete(KeyUtils.fans(id));
	}

	public List<Map<Object, Object>> askForCandidate(String uid,
			Map<String, Object> data) throws Exception {
		String to = (String) data.get("to");
		String word = (String) data.get("words");
		Integer flower = (Integer) data.get("flower");
		RedisSet<String> fans = this.fans(to);
		if (fans.size() >= 10) {
			throw new Exception("候选人数已超过最高限制10人");
		}

		BoundHashOperations<String, String, String> mine = template
				.boundHashOps(KeyUtils.uid(uid));
		// Map<Object, Object> mine = userManager.findUser(id);
		Map<String, String> f1 = this.friendService.friend(uid, to);
		if (f1.size() > 0) {
			mine.put("sendAssoValue", f1.get("assoValue"));
		} else {
			mine.put("sendAssoValue", "0");
		}
		Map<String, String> f2 = this.friendService.friend(to, uid);
		if (f2.size() > 0) {
			mine.put("sendName", f2.get("nikeName"));
		} else {
			mine.put("sendName", mine.get("id"));
		}

		mine.put("friendDesc", word);
		mine.put("sendFlowers", String.valueOf(flower));
		this.fans(to).add(uid);

		List<Map<Object, Object>> list = new ArrayList<Map<Object, Object>>();
		for (String f : this.fans(to)) {
			Map<Object, Object> map = new HashMap<Object, Object>();
			map.put("user", userService.findUser(f));
			map.put("report", userService.findReport(f));
			list.add(map);
		}
		return list;
	}
}
